grammar PseudoGrep;

options
{
	language=C;
}

tokens {
	MAS 	= '+' ;
	AST	= '*' ;
	BAR	= '|' ;
	PREG	= '?' ;
	APAR	= '(' ;	
	CPAR	= ')' ;	
	ANY	= '.';
}

@parser::includes{
	#include "AFND.h"
	#include <iostream>
	using namespace std;
	
	AFND* er2afnd(char* er, set<char>& _alfabeto);
}

@members
{

 #include "PseudoGrepLexer.h"

 set<char> alfabeto;


AFND* er2afnd(char* er, set<char>& _alfabeto){

    pANTLR3_INPUT_STREAM           input;
    pPseudoGrepLexer               lex;
    pANTLR3_COMMON_TOKEN_STREAM    tokens;
    pPseudoGrepParser              parser;

    input  = antlr3NewAsciiStringInPlaceStream 
     			((uint8_t*)er, strlen(er), (uint8_t*)"ER de entrada");
    lex    = PseudoGrepLexerNew                (input);
    tokens = antlr3CommonTokenStreamSourceNew  (ANTLR3_SIZE_HINT, TOKENSOURCE(lex));
    parser = PseudoGrepParserNew               (tokens);


    alfabeto = _alfabeto;

    AFND* afnd = parser->regex(parser);
    
    parser ->free(parser);
    tokens ->free(tokens);
    lex    ->free(lex);
    input  ->close(input);

    return afnd;
 }

}

/* PARSER */
regex	returns [AFND* afnd]
	:	re=expr EOF {
			$afnd = re;
		}
	; 


expr returns [AFND* afnd]
@init{
	afnd2 = NULL;
}
	: 	afnd1=concatenacion[NULL] afnd2=alternativa[afnd1]? {
			if(afnd2!=NULL)
				$afnd = afnd2;
			else
				$afnd = afnd1;
		}
	;

concatenacion [AFND* izq] returns [AFND* afnd]
@init{
	afnd2 = NULL;
}
	: 	afnd1=cuantificada {
			if(izq!=NULL)
				izq->concatenar(*afnd1);
			else
				izq = afnd1;
		}
		afnd2=concatenacion[izq]?{
			if(afnd2!=NULL)
				$afnd = afnd2;
			else
				$afnd = izq;
		}
	;
	
cuantificada returns [AFND* afnd]
@init{
	operUnaria = 0;
}
	:	(afnd1=atom | afnd1=bloque) (operUnaria=unarias)? {
			$afnd = afnd1;
			switch(operUnaria){
				case '*':
					$afnd->clausurar();
					break;
				case '+':
					$afnd->clausurarPositivamente();				
					break;
				case '?':
					$afnd->hacerOpcional();				
					break;
			}
		}
	;

alternativa [AFND* izq] returns [AFND* afnd]
@init{
	afnd2 = NULL;
}
	: 	BAR afnd1=concatenacion[NULL]{
			izq->alternativa(*afnd1);
		}
		afnd2=alternativa[izq]?{
			if(afnd2!=NULL)
				$afnd = afnd2;
			else
				$afnd = izq;
		}
	;

// La semantica simplifica multiples operaciones unarias a una sola
unarias	returns [char oper]
@init{
	$oper = '*';
	simbolo2 = 0;
}
	:	( simbolo1=AST | simbolo1=MAS | simbolo1=PREG) simbolo2=unarias? {
		char s1 = ($simbolo1.text->chars)[0];
		if(simbolo2==0 || s1==simbolo2)
			$oper = s1;
	}
	;

atom returns [AFND* afnd]
@init{
	$afnd = NULL;
}
	:	car = CAR {
			$afnd = new AFND($car.text->chars[0], alfabeto);
		}
	| 	ANY {
			$afnd = new AFND(alfabeto);
		}
	;

bloque	returns [AFND* afnd]
	:	APAR afnd1 = expr CPAR {
			$afnd = afnd1;
		}
	;

/* LEXER */
CAR	:	'a'..'z' | 'A'..'Z' | '0'..'9';
